package com.gao.b_stream.b;


import org.junit.Test;

import java.util.Arrays;
import java.util.Date;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author gao
 * @time 2020/07/22 16:02:45
 * Java8 Stream 从0到入门
 */
public class App {

    @Test
    public void test() {
        Stream.of("apple", "banana", "cucumber", "durian")
                .map(s -> s.length())
                .forEach(i -> System.out.println(i));
    }

    @Test
    public void test2() {
        Stream.of("apple", "banana", "cucumber", "durian")
                .map(String::toUpperCase)
                .forEach(System.out::println);
    }

    @Test
    public void test3() {
        Stream.of("apple", "banana", "cucumber", "durian")
                .mapToInt(String::length)
                .forEach(System.out::println);
    }

    @Test
    public void test4() {
        Stream.of("a-b-c-d", "1-2-3-4", "甲-乙-丙-丁")
                .map(e -> e.split("-"))
                .forEach(e -> System.out.println(e));

        System.out.println("==============================================");

        Stream.of("a-b-c-d", "1-2-3-4", "甲-乙-丙-丁")
                .map(e -> Arrays.toString(e.split("-")))
                .forEach(e -> System.out.println(e));

        System.out.println("==============================================");

        Stream.of("a-b-c-d", "1-2-3-4", "甲-乙-丙-丁")
                .map(e -> Stream.of(e.split("-")))
                .forEach(e -> System.out.println(e));

        System.out.println("==============================================");

        Stream.of("a-b-c-d", "1-2-3-4", "甲-乙-丙-丁")
                .flatMap(e -> Stream.of(e.split("-")))
                .forEach(e -> System.out.println(e + "~"));
    }

    // limit 选取前N个元素
    @Test
    public void test5() {
        Stream.of("apple", "banana", "cucumber", "durian")
                .limit(3)
                .forEach(e -> System.out.println(e));
    }

    @Test
    public void test6() {
        Stream.of("周杰伦", "双节棍", "周润发", "周杰伦", "双节棍", "周润发")
                .distinct()
                .forEach(e -> System.out.println(e));
    }

    // filter 对某些元素进行过滤，不符合筛选条件的将无法进入流的下游
    @Test
    public void test7() {
        Stream.of(10, 20, 30, 40, 50, 60, 70, 80, 90, 100)
                .filter(e -> e >= 50)
                .forEach(e -> System.out.println(e));
    }

    // peek 挑选 ，将元素挑选出来，可以理解为提前消费
    // 毕竟peek还是一个中间操作，所以在peek之后，可以调用forEach。
    // 但是在forEach之后，则不能再调用peek了。
    @Test
    public void test8() {
        User u = new User(1, "andy", new Date(), 2000d);
        User u2 = new User(2, "bob", new Date(), 3000d);
        User u3 = new User(3, "candy", new Date(), 1000d);

        Stream.of(u, u2, u3)
                .peek(e -> {
                    String name = e.getName();
                    e.setName(name + "~~~");
                })
                .forEach(e -> System.out.println(e));
    }

    // skip 跳过前N个元素
    @Test
    public void test9() {
        Stream.of(11, 22, 33, 44, 55, 66, 77, 88, 99, 100)
                .skip(4)
                .forEach(e -> System.out.println(e));
    }

    // sorted 排序 底层依赖Comparable 实现，也可以提供自定义比较器
    @Test
    public void test10() {
        Stream.of(5, 1, 7, 4, 2, 3, 9, 7, 8, 0)
                .sorted()
                .forEach(e -> System.out.println(e));
    }

    // 这里使用自定义比较，当然User 可以实现Comparable 接口
    @Test
    public void test11() {
        User u = new User(1, "andy", new Date(), 2000d);
        User u2 = new User(2, "bob", new Date(), 3000d);
        User u3 = new User(3, "candy", new Date(), 1000d);

        Stream.of(u, u2, u3)
                .sorted((e1, e2) -> -e1.getBalance().compareTo(e2.getBalance()))
                .forEach(e -> System.out.println(e));
    }

    // collect 收集，使用系统提供的收集器可以将最终的数据流收集到List，Set，Map等容器中。
    @Test
    public void test12() {
        Stream.of("apple", "banana", "orange", "waltermaleon", "grape")
                .collect(Collectors.toSet())
                .forEach(e -> System.out.println(e));
        /*
            咦？不是说终止操作符只能使用一次吗，为什么这里调用了forEach 呢？
            这里最后的forEach其实不是Stream中的api，而是Set的api！参考test13
         */
    }

    @Test
    public void test13() {
        Set<String> set = Stream.of("apple", "banana", "orange", "waltermaleon", "grape")
                .collect(Collectors.toSet());

        set.forEach(e -> System.out.println(e));
    }


    // count 统计数据流中的元素个数，返回的是long 类型
    // findFirst 获取流中的第一个元素
    // findAny 获取流中任意一个元素（不是随机，每次都是一个固定的结果）
    @Test
    public void test14() {
        long count = Stream.of("apple", "banana", "orange", "waltermaleon", "grape")
                .count();
        System.out.println("count = " + count);

        Optional<String> first = Stream.of("apple", "banana", "orange", "waltermaleon", "grape")
                .findFirst();
        System.out.println("first = " + first.get());

        Optional<String> any = Stream.of("apple", "banana", "orange", "waltermaleon", "grape")
                .findAny();
        System.out.println("any = " + any.get());

    }

    /*
        noneMatch 数据流中得没有一个元素与条件匹配的
        这里 的作用是是判断数据流中 一个都没有与foo 相等元素 ，但是流中存在 foo ，所以最终结果应该是false
     */
    @Test
    public void test15() {
        boolean bb = Stream.of("foo bar baz qux".split(" "))
                .noneMatch(e -> "foo".equals(e));

        System.out.println("bb = " + bb);
    }

    /*
        allMatch
     */
    @Test
    public void test16() {
        boolean bb = Stream.of(15, 20, 25, 30, 35, 40, 45, 50)
                .allMatch(e -> e > 10);

        System.out.println("bb = " + bb);
    }

    /*
        anyMatch
     */
    @Test
    public void test17() {
        boolean bb = Stream.of(5, 20, 25, 30, 35, 40, 45, 50)
                .anyMatch(e -> e < 10);

        System.out.println("bb = " + bb);
    }

    /*
        min、max
     */
    @Test
    public void test18() {
        Optional<String> minElt = Stream.of("aaaa bbb cc z".split(" "))
                .min((e1,e2) -> new Integer(e1.length()).compareTo(e2.length()));

        // print z
        System.out.println(minElt.get());
    }


    // reduce 是一个规约操作，所有的元素归约成一个，比如对所有元素求和等
    @Test
    public void test19() {
        Integer sum = Stream.of(1, 2, 3, 4, 5)
                .reduce(0, (e1, e2) -> {
                    System.out.println(e1 + " " + e2);
                    return e1 + e2;
                });

        System.out.println("sum = " + sum);

         /*
            print:
            0 1
            1 2
            3 3
            6 4
            10 5
            sum = 15
         */
    }

    // toArray
    @Test
    public void test20() {
        Object[] arr = Stream.of(11, 22, 33, 44, 55, 66, 77, 88, 99, 100)
                .toArray();

        for (Object o : arr) {
            System.out.println(o);
        }
    }

}
